<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>JS分享</title>
    <link rel="stylesheet" href="static/vendor/reveal-3.0/css/reveal.css">
    <link rel="stylesheet" href="static/vendor/reveal-3.0/css/theme/sannychan-reveal.css" id="theme">
    <link rel="stylesheet" href="static/vendor/reveal-3.0/lib/css/zenburn.css">
</head>
<body>
<div class="reveal">
    <div class="slides">
        <section style="text-align: center">
            <h1>JS分享</h1>
            <span style="float: right;margin-top: 50px">陈胜利</span>
        </section>
        <section>
            <h2>Javascript诞生记</h2>
            1995<br>Sun<br> Oak—>Java<br>Write Once, Run Anywhere<br>网景(Netscape) <br>网页脚本语言<br>"Brendan Eich"<br>
            10天<br>
        </section>
        <section>
            <h2>设计思路</h2>
            <pre>（1）借鉴C语言的基本语法；
（2）借鉴Java语言的数据类型和内存管理；
（3）借鉴Scheme语言，将函数提升到"第一等公民"（first class）的地位；
（4）借鉴Self语言，使用基于原型（prototype）的继承机制。</pre>
            <h2>产物</h2>（简化的）函数式编程+（简化的）面向对象编程<br>
        </section>
        <section><h2>作者评价</h2>
            <blockquote>"与其说我爱Javascript，不如说我恨它。它是C语言和Self语言一夜情的产物。<br>
                十八世纪英国文学家约翰逊博士说得好：'它的优秀之处并非原创，它的原创之处并不优秀。'<br>
                （the part that is good is not original, and the part that is original is not good.）"<br>
            </blockquote>

        </section>
        <section>
            <h2>目录</h2>
            <ul>
                <li>数据类型</li>
                <li>对象类型</li>
                <li>原型</li>
                <li>面向对象</li>
                <li>this</li>
                <li>闭包</li>
                <li>附录</li>
            </ul>
        </section>
        <section>
            <h2>数据类型</h2>
            <h3>基础数据类型：</h3>
            Undefined(undefined)<br>
            Null(null)<br>
            Boolean(true和false)<br>
            Number(整数、浮点数、指数、NaN、Infinity、8|10|16进制等)<br>
            String<br>

            <h3>复合数据类型</h3>
            Object，数组
        </section>
        <section>
            <pre><code class="javascript" data-trim contenteditable="true">
                var func = function(){
                alert("func")
                }
                console.log("typeof null:"+typeof null);
                console.log("typeof undefined:"+typeof undefined);
                console.log("typeof \"sss\":"+typeof "sss");
                console.log("typeof 1:"+typeof 1);
                console.log("typeof 1.1:"+typeof 1.1);
                console.log("typeof NaN:"+typeof NaN);
                console.log("typeof func:"+typeof func);
            </code></pre>
        </section>
        <section>
            null属于对象（object）的一种，意思是该对象为空；undefined则是一种数据类型，表示未定义。
            <pre><code class="javascript" data-trim contenteditable="true">
                var foo;
                console.log("foo == null: "+(foo == null));
                console.log("foo == undefined: "+(foo == undefined));
                console.log("foo === null: "+(foo === null));
                console.log("foo === undefined: "+(foo === undefined));
            </code></pre>
        </section>
        <section>
            <h2>对象类型</h2>

            <h3>本地对象</h3>
            由js定义的类
            <h3>内置对象</h3>
            内置对象都是本地对象，使用时不需要实例化，JS执行时已经初始化完成。
            <h3>宿主对象</h3>
            主页是BOM和DOM对象
            <br><a href="http://www.w3school.com.cn/js/pro_js_object_types.asp" target="_blank">链接：JS对象类型</a>
        </section>
        <section>
            <h2>BOM和DOM对象</h2>
            <img src="static/img/browser_objects.png">
            <br><a href="http://www.w3school.com.cn/js/js_obj_htmldom.asp" target="_blank">链接：BOM和DOM对象</a>
        </section>
        <section>
            <h2>原型</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                Number.prototype.add = function (x) {
                return this + x;
                };
                console.log("8.add(2) : "+ (8.add(2)));
                console.log("8['add'](2) : " + (8['add'](2)) );
                console.log("(8).add(2)) : "+((8).add(2)) );
                console.log("8..add(2)) : "+(8..add(2)) );
            </code></pre>

        </section>
        <section>
            <h2>面向对象</h2>
            &nbsp;&nbsp;一切事物皆对象，通过面向对象的方式，将现实世界的事物抽象成对象，现实世界中的关系抽象成类、继承，帮助人们实现对现实世界的抽象与数字建模。<br>
            &nbsp;&nbsp;“面向对象编程”主要是指在程序中采用封装、继承、多态等进行设计的编程思想。
        </section>
        <section>
            <h2>面向过程和面向对象的一点区别</h2>
            假设在一段游戏的代码中，有这样一个场景：有1000吨的货物，要从西安运到北京。<br>

            <h3>面向过程(面向函数)思考：</h3>
            <span class="fragment">&nbsp;&nbsp;从西安到北京这一路上会有那些障碍？那些路是用车送的，那些路是用人送的，可能有什么突发情况（山洪，泥石流，土匪打劫）</span>
            <span class="fragment"><h3>面向对象思考：</h3></span>
            <span class="fragment">&nbsp;&nbsp;恩，这么复杂的送货任务，总要有个人来做吧，于是就搞个押运员去弄，定义一个类：Escort<span style="color:red;">——>定义类(封装性)</span></span><br>
            <span class="fragment">&nbsp;&nbsp;押运员首先得是个人，应该有人的一切属性（如眼耳鼻舌），从已经定义好的Person继承就好了，于是，Escort 就成了People的子类，他可以享用People的一切属性和方法<span
                    style="color:red;">——>继承</span></span><br>
            <span class="fragment">&nbsp;&nbsp;Person应该具有处理异常情况的方式:handleEmergency()，比如前方泥石流，普通人可能就会原地等待，但Escort就会选择绕道而行，毕竟页面正在倒计时！<span
                    style="color:red;">——>多态</span></span>
        </section>
        <section>
            <h2>面向对象-封装-1</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var csl = {}; // 创建一个空对象
                　　　　csl.name = "陈胜利"; // 按照原型对象的属性赋值
                　　　　csl.age = "30";
                console.log("csl:",csl);
                var zs = {}; // 创建一个空对象
                　　　　zs.name = "张三"; // 按照原型对象的属性赋值
                　　　　zs.age = "40";
                console.log("zs:",zs);
            </code></pre>
        </section>
        <section>
            <h2>面向对象-封装-2</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var Person = function(name,age){
                return {
                　　　　　　name:name,
                　　　　　　age:age
                　　　　}
                }
                var csl = Person("陈胜利","30");
                var zs = Person("张三","40");
                console.log("csl:",csl);
                console.log("zs:",zs);
            </code></pre>
        </section>
        <section>
            <h2>面向对象-封装-3</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var Person = function (name, age) {
                this.name = name;
                this.age = age;
                this.handleEmergency=function(){console.log(name," wait for clear!");}
                }
                var csl = new Person("陈胜利", 30);
                csl.handleEmergency();
                Person.prototype.type="human";
                console.log("Person.prototype.type:",csl.type);
            </code></pre>
        </section>
        <section>
            <h2>原型的优势</h2>
            <pre>

每一个构造函数都有一个prototype属性，指向另一个对象。这个对象的所有属性和方法，都会被构造函数的实例继承。

所有实例的type属性和eat()方法，其实都是同一个内存地址，指向prototype对象，因此就提高了运行效率。
            </pre>
        </section>
        <section>
            <h2>面向对象-继承-无构造函数-1</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var Person = {name:"陈胜利",age:"30"};
                var Escort = {company:"顺丰"};
                function clone(obj) {
                　　　　function F() {}
                　　　　F.prototype = obj;
                　　　　return new F();
                }
                Escort = clone(Person);
                console.log("Escort:",Escort);
                Escort.company = "顺丰";
                console.log("Escort:",Escort);
                Escort.name = "隔壁老王";
                console.log("Escort:",Escort);
            </code></pre>
        </section>
        <section>
            <h2>面向对象-继承-无构造函数-2</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var Person = {name:"陈胜利",age:"30"};
                var Escort = {company:"顺丰"};
                function extend(obj) {
                　　　　var c = {};
                　　　　for (var i in obj) {
                　　　　　　c[i] = obj[i];
                　　　　}
                　　　　return c;
                　　}
                Escort = extend(Person);
                console.log("Escort:",Escort);
                Escort.company = "顺丰";
                console.log("Escort:",Escort);
                Escort.name = "隔壁老王";
                console.log("Escort:",Escort);
            </code></pre>
            注意：如果Person含有Date等对象时，子对象的该属性是指向父属性的指针。——浅拷贝<br>
            <a href="http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html"
               target="_blank">链接：JS非构造函数的继承</a>
        </section>
        <section>
            <h2>面向对象-继承-构造函数</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var Person = function (name, age) {
                this.name = name;
                this.age = age;
                }
                var Escort = function(name, age, company){
                Person.apply(this,arguments);
                this.company = company;
                }
                var Escort2 = function(name, age, company){
                Person.call(this,arguments[0],arguments[1]);
                this.company = company;
                }
                var ls1 = new Escort("李四","40","顺丰");
                var ls2 = new Escort2("李四","40","顺丰");
                console.log("ls1:",ls1);
                console.log("ls2:",ls2);
            </code></pre>
            <a href="http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html">链接：JS构造函数继承的五种方式</a>
        </section>
        <section>
            <h2>面向对象-多态</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                function test(a, b){
                var a = a;
                var b = b;
                if (typeof a == "number" && typeof b == "number") {
                console.log("number, a*b:",a * b);
                } else if (typeof a == "string" && typeof b == "string") {
                console.log("string, a+b:",a+" " +b);
                } else {
                console.log("wrong argument type!");
                }
                }
                test(3,4);
                test("hello","world");
                test(3,"world");
            </code></pre>
        </section>
        <section>
            <h2>this-1</h2>
            this在不同场景下，this的值是变化。
            原则：this指的是调用函数的那个对象。
            全局情况下，this就是指Global。<br><a href="this-1.html" target="_blank">链接：演示-this-1</a>
                <pre><code class="javascript" data-trim contenteditable="true">
                    this.a = 10;
                    console.log("this:", this);
                </code></pre>
            <a href="http://www.quirksmode.org/js/this.html" target="_blank">链接：this详解</a>
        </section>
        <section>
            <h2>this-2</h2>
            作为某个对象的方法调用，this是指该对象。
            <pre><code class="javascript" data-trim contenteditable="true">
                this.x =100;
                function test(){
                　　　　console.log("this.x:"+this.x);
                　　}
                　　var o = {};
                　　o.x = 1;
                　　o.m = test;
                　　o.m(); // 1
            </code></pre>
        </section>
        <section>
            <h2>this-3</h2>
            就是通过构造函数生成一个新对象（object），this指此新对象。
            <pre><code class="javascript" data-trim contenteditable="true">
                var x = 2;
                　　function test(){
                　　　　this.x = 1;
                　　}
                　　var o = new test();
                console.log("o.x",o.x); //2
                　　console.log("x",x); //2
            </code></pre>
        </section>
        <section>
            <h2>this-4</h2>
            函数调用中手动设置this,使用call和apply。
            <br><a href="this-4.html" target="_blank">链接：演示-this-4</a>
        </section>
        <section>
            <h2>闭包</h2>
            JS在函数内部可以直接读取全局变量,在函数外部是无法读取函数内的局部变量。<br>
            那如何从外部读取局部变量？
            <pre><code class="javascript" data-trim contenteditable="true">
                var a = "a";
                function f1(){
                　　console.log("a:",a);
                }
                f1();

                function f2(){
                var b = "b";
                }
                f2();
                console.log("b:",b);
            </code></pre>
        </section>
        <section>
            <h2>闭包</h2>
            那如何从外部读取局部变量？
            <pre><code class="javascript" data-trim contenteditable="true">
                function f1(){
                　　　　var b="b";
                　　　　function f2(){
                　　　　　　console.log("b:",b);
                　　　　}
                　　　　return f2;
                　　}
                　　var result=f1();
                　　result(); // 999
            </code></pre>
            闭包可以简单理解成"定义在一个函数内部的函数",可将函数内部和函数外部连接起来。
        </section>
        <section>
            <h2>闭包-用途</h2>
            <ul>
                <li>读取函数内部的变量</li>
                <li>让变量的值始终保持在内存中</li>
            </ul>
            <pre><code class="javascript" data-trim contenteditable="true">
                function f1(){
                　　　　var n=999;
                　　　　nAdd=function(){n+=1}
                　　　　function f2(){
                　　　　　　console.log(n);
                　　　　}
                　　　　return f2;
                　　}
                　　var result=f1();
                　　result(); // 999
                　　nAdd();
                　　result(); // 1000
            </code></pre>
            <span class="fragment">为什么会这样呢？<br>
                原因就在于f1是f2的父函数，而f2被赋给了一个全局变量，这导致f2始终在内存中，而f2的存在依赖于f1，
                因此f1也始终在内存中，不会在调用结束后，被垃圾回收机制（garbage collection）回收。</span><br>
            <span class="fragment"><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures" target="_blank">链接：闭包详解</a></span>
        </section>
        <section>
            <h2>闭包-实例-1</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var name = "The Window";
                　　var object = {
                　　　　name : "My Object",
                　　　　getNameFunc : function(){
                　　　　　　return function(){
                　　　　　　　　return this.name;
                　　　　　　};
                　　　　}
                　　};
                　　console.log("1-object.getNameFunc()():",object.getNameFunc()());
            </code></pre>
        </section>
        <section>
            <h2>闭包-实例-2</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var name = "The Window";
                　　var object = {
                　　　　name : "My Object",
                　　　　getNameFunc : function(){
                　　　　　　var that = this;
                　　　　　　return function(){
                　　　　　　　　return that.name;
                　　　　　　};
                　　　　}
                　　};
                　　console.log("2-object.getNameFunc()():",object.getNameFunc()());
            </code></pre>
        </section>
        <section>
            <h2>闭包-实例-3</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var makeCounter = function() {
                var privateCounter = 0;
                function changeBy(val) {
                privateCounter += val;
                }
                return {
                increment: function() {
                changeBy(1);
                },
                decrement: function() {
                changeBy(-1);
                },
                value: function() {
                return privateCounter;
                }
                }
                };
                var counter1 = makeCounter();
                console.log("counter1.value():",counter1.value());
                counter1.increment();
                counter1.increment();
                console.log("counter1.value():",counter1.value());
                var counter2 = makeCounter();
                console.log("counter2.value():",counter2.value());
            </code></pre>
        </section>
        <section>
            <h2>闭包-循环中的闭包</h2>
            <a href="closure-1.html" target="_blank">链接：示例-1</a><br>
            <a href="closure-2.html" target="_blank">链接：示例-2</a>
        </section>
        <section>
            <h2>数组for...in</h2>
            <pre><code class="javascript" data-trim contenteditable="true">
                var cars = [ "Saab", "Volvo", "BMW" ];
                Array.prototype.benz = "Benz";
                for(var i=0;i&ltcars.length;i++){
                console.log("for loop car:",cars[i]);
                }
                for (var car in cars) {
                console.log("for in car:",cars[car]);
                }
            </code></pre>
            <span class="fragment">
                建议不要对数组执行for in循环，for in循环总是会访问该对象的原型,看原型上是否有属性,这在无意中就给遍历增加了额外的压力。
            </span>
        </section>
        <section>
            <h2></h2>
            自动插入行尾分号。<br>
            如果下一行的第一个字元（token）是下面这五个字符之一，Javascript将不对上一行句尾添加分号："("、"["、"/"、"+"和"-"
            <pre><code class="javascript" data-trim contenteditable="true">
                var a = function(){
                　　　　return
                　　　　　　{
                　　　　　　　　i=1
                　　　　　　};
                　　}
                console.log("a(): ",a());
                var y = 10;
                x = y
                (function (){
                return "7777";
                })();
                console.log("x: ",x);
            </code></pre>
        </section>
        <section>
            <h2>附录</h2>
            <a href="http://www.open-open.com/lib/view/open1426514414820.html" target="_blank">链接：JavaScript 开发的45个经典技巧</a><br>
            <a href="http://uml.org.cn/site/201105032.asp" target="_blank">链接：开发者最容易犯的13个JavaScript错误</a><br>
            <a href="http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html" target="_blank">链接：深入理解JavaScript系列</a><br>
            <a href="http://www.ruanyifeng.com/blog/javascript/" target="_blank">链接：阮一峰的JavaScript系列</a><br>
        </section>

    </div>
</div>
</body>
<script src="static/vendor/reveal-3.0/js/reveal.js"></script>
<script src="static/vendor/reveal-3.0/lib/js/head.min.js"></script>
<script src="static/vendor/jquery-1.11.0.min.js"></script>

<script>
    var codeMap = {};
    $('code').each(function (index, element) {
        var section = $(element).parent().parent();
        var dataState = "code-" + index;
        $(section).attr("data-state", dataState);
        var code = $(element).text();
        codeMap[dataState] = code;
    });
    Reveal.initialize({
        controls: false,
        progress: true,
        history: true,
        center: false,
        mouseWheel: true,
        //autoSlide: 3000, //可以用data-autoslide控制
        transition: 'slide', // none/fade/slide/convex/concave/zoom
        dependencies: [
            {
                src: 'static/vendor/reveal-3.0/plugin/highlight/highlight.js', async: true, condition: function () {
                return !!document.querySelector('pre code');
            }, callback: function () {
                hljs.initHighlightingOnLoad();
            }
            }
        ]
    });

    for (var key in codeMap) {
        Reveal.addEventListener(key, function (event) {
            var codeKey = event.type;
            var code = codeMap[codeKey];
            eval(code);
        });
    }
</script>
</html>